### 代码说明：
# 1. ** 类结构 **：实现了一个可控制的视频采集类，支持启动 / 停止采集、获取当前帧
# 2. ** 线程处理 **：使用单独线程进行视频采集，避免阻塞UI界面
# 3. ** 线程安全 **：通过锁机制确保帧数据的安全访问
# 4. ** 兼容性 **：
# - 支持摄像头（默认使用0号摄像头）和本地视频文件
# - 与UI中的调用方式完全匹配（`start()` / `stop()` / `get_frame()` / `is_running`）
# 5. ** 帧率控制 **：限制采集帧率为30FPS，平衡性能与流畅度
import cv2
import threading
import time

class VideoCapture:
    """视频采集类，支持从摄像头或本地文件捕获视频流"""

    def __init__(self, source=0):
        """
        初始化视频采集器
        参数:
            source: 视频源，0表示默认摄像头，也可以是视频文件路径
        """
        self.source = source
        self.cap = None
        self.running = False  # 采集状态标志
        self.current_frame = None  # 当前帧缓存
        self.lock = threading.Lock()  # 线程锁，确保帧数据访问安全

    def start(self):
        """启动视频采集（在新线程中运行）"""
        if self.running:
            return  # 已在运行则直接返回

        self.running = True
        # 创建并启动采集线程
        self.thread = threading.Thread(target=self._capture_loop)
        self.thread.daemon = True  # 守护线程，主程序退出时自动结束
        self.thread.start()

    def stop(self):
        """停止视频采集"""
        self.running = False
        if self.thread.is_alive():
            self.thread.join()  # 等待线程结束
        if self.cap:
            self.cap.release()  # 释放摄像头/文件资源
        self.cap = None

    def _capture_loop(self):
        """视频采集循环（内部线程函数）"""
        self.cap = cv2.VideoCapture(self.source)
        if not self.cap.isOpened():
            print(f"无法打开视频源: {self.source}")
            self.running = False
            return

        while self.running:
            ret, frame = self.cap.read()
            if not ret:
                print("视频采集结束或出错")
                self.running = False
                break

            # 线程安全地更新当前帧
            with self.lock:
                self.current_frame = frame.copy()

            # 控制采集帧率（约30FPS）
            time.sleep(1 / 30)

    def get_frame(self):
        """获取当前帧的副本"""
        with self.lock:
            if self.current_frame is not None:
                return self.current_frame.copy()
            return None

    @property
    def is_running(self):
        """返回当前采集状态"""
        return self.running
